/**
 * Copyright (C) 2011 Audit Logger Project. All rights reserved.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.auditlogger.cli;

import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.DSAParams;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;

import org.auditlogger.config.ConfigurationServices;
import org.auditlogger.config.spi.PropertiesConfigurator;
import org.auditlogger.util.Base64EncoderDecoder;

/**
 * 
 * @author Ravi Sharda
 */
public class SigningKeyPairGenerator {

	private static PropertiesConfigurator config = ConfigurationServices.getPropertiesConfigurator();

	private final static String signatureAlgorithm = config.getSignatureAlgorithm(); //"SHA1withDSA";
	private static int signatureKeyLength = 1024;


	private static KeyPairGenerator createKeyPairGenerator() throws NoSuchAlgorithmException {
		String sigAlg = signatureAlgorithm.toLowerCase();
		if ( sigAlg.endsWith("withdsa") ) {
			//
			// Admittedly, this is a kludge. However for Sun JCE, even though
			// "SHA1withDSA" is a valid signature algorithm name, if one calls
			//      KeyPairGenerator kpg = KeyPairGenerator.getInstance("SHA1withDSA");
			// that will throw a NoSuchAlgorithmException with an exception
			// message of "SHA1withDSA KeyPairGenerator not available". Since
			// SHA1withDSA and DSA keys should be identical, we use "DSA"
			// in the case that SHA1withDSA or SHAwithDSA was specified. This is
			// all just to make these 2 work as expected. Sigh. (Note:
			// this was tested with JDK 1.6.0_21, but likely fails with earlier
			// versions of the JDK as well.)
			//
			sigAlg = "DSA";
		} else if ( sigAlg.endsWith("withrsa") ) {
			// Ditto for RSA.
			sigAlg = "RSA";
		} else {
			sigAlg = signatureAlgorithm;
		}
		KeyPairGenerator keyGen = KeyPairGenerator.getInstance(sigAlg);
		return keyGen;
	}

	// Set up signing key pair using the master password and salt. Called (once)
	// from the JavaEncryptor CTOR.
	private static void initializeKeyPairGenerator(KeyPairGenerator keyGen, 
			int signatureKeyLength, String secureRandomAlgorithm) throws NoSuchAlgorithmException {

		SecureRandom prng = SecureRandom.getInstance(secureRandomAlgorithm);

		// Note: The SecureRandom implementation attempts to completely randomize the 
		// internal state of the generator itself unless the caller follows the call to the 
		// getInstance method with a call to the setSeed method. So if you had a specific seed 
		// value that you wanted used, you would call the following prior to the initialize call:
		prng.setSeed(90);

		keyGen.initialize(signatureKeyLength, prng);
	}

	private static KeyPair generateKeyPair(KeyPairGenerator keyGen) {
		return keyGen.generateKeyPair();
	}

	public static void main (String[] args) throws Exception {

		KeyPairGenerator keyPairGenerator = createKeyPairGenerator();
		initializeKeyPairGenerator(keyPairGenerator, signatureKeyLength, config.defaultRandomAlgorithm());
		KeyPair keyPair = generateKeyPair(keyPairGenerator);
		
		String eol = System.getProperty("line.separator", "\n"); // So it works on Windows too.
		System.out.println( eol + "Copy and paste these lines into your configuration.properties" + eol);
		System.out.println( "#==============================================================");
		System.out.println( "Signature.PrivateKey=" + Base64EncoderDecoder.encodeForBase64( 
				keyPair.getPrivate().getEncoded()));
		System.out.println();
		System.out.println(keyPair.getPrivate().getClass());
		System.out.println();
		System.out.println( "Signature.PublicKey=" + Base64EncoderDecoder.encodeForBase64(
				keyPair.getPublic().getEncoded()));
		System.out.println();
		printParams((DSAPrivateKey)keyPair.getPrivate(), (DSAPublicKey)keyPair.getPublic());
		System.out.println( "#==============================================================" + eol);
	}
	
	private static void printParams(DSAPrivateKey privateKey, DSAPublicKey publicKey) {
		System.out.println("DSA Params:");
		DSAParams dsaParams = privateKey.getParams();
		BigInteger p = dsaParams.getP();
		System.out.println("Signature.p=" + p);

		BigInteger q = dsaParams.getQ();
		System.out.println("Signature.q=" + q);

		BigInteger g = dsaParams.getG();
		System.out.println("Signature.g=" + g);

		BigInteger x = privateKey.getX();
		System.out.println("Signature.x=" + x);

		BigInteger y = publicKey.getY();
		System.out.println("Signature.y=" + y);
	}

}
